/* @(#)NodeFragGovernance.java
** 
** Copyright (C) 2012 by Steven D. Stamps
**
**             Trademarks & Copyrights
** Flywheel Management Science(TM), Flywheel Management Model(TM),
** Flywheel Story Editor(TM) and FlywheelMS(TM) are exclusive trademarks
** of Steven D. Stamps and may only be used freely for the purpose of
** identifying the unforked version of this software.  Subsequent forks
** may not use these trademarks.  All other rights are reserved.
**
** DecKanGL (Decorated Kanban Glyph Language) and TribKn (Tribal Knowledge)
** are also exclusive trademarks of Steven D. Stamps.  These may be used
** freely within the unforked FlywheelMS application and documentation.
** All other rights are reserved.
**
** gConGUI (game Controller Graphical User Interface) is an exclusive
** trademark of Steven D. Stamps.  This trademark may be used freely
** within the unforked FlywheelMS application and documentation.
** All other rights are reserved.
**
** Trademark information is available at
** <http://www.flywheelms.com/trademarks>
**
** Flywheel Management Science(TM) is a copyrighted body of management
** metaphors, governance processes, and leadership techniques that is
** owned by Steven D. Stamps.  These copyrighted materials may be freely
** used, without alteration, by the community (users and developers)
** surrounding this GPL3-licensed software.  Additional copyright
** information is available at <http://www.flywheelms.org/copyrights>
**
**              GPL3 Software License
** This program is free software: you can use it, redistribute it and/or
** modify it under the terms of the GNU General Public License, version 3,
** as published by the Free Software Foundation. This program is distributed
** in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
** even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
** PURPOSE.  See the GNU General Public License for more details. You should
** have received a copy of the GNU General Public License, in a file named
** COPYING, along with this program.  If you cannot find your copy, see
** <http://www.gnu.org/licenses/gpl-3.0.html>.
*/

package com.flywheelms.library.fmm.node.impl.nodefrag;

import java.util.Collection;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;

import com.flywheelms.library.fca.FlywheelCommunityAuthentication;
import com.flywheelms.library.fmm.deckangl.DecoratorGovernance;
import com.flywheelms.library.fmm.helper.FmmDateHelper;
import com.flywheelms.library.fmm.node.NodeId;
import com.flywheelms.library.fmm.node.impl.enumerator.AssignmentCommitmentType;
import com.flywheelms.library.fmm.node.impl.enumerator.FmmNodeDictionary;
import com.flywheelms.library.fmm.node.impl.enumerator.GovernanceParticipationType;
import com.flywheelms.library.fmm.node.impl.enumerator.GovernanceRole;
import com.flywheelms.library.fmm.node.impl.enumerator.GovernanceTarget;
import com.flywheelms.library.fmm.node.impl.headline.CommunityMember;
import com.flywheelms.library.fmm.node.interfaces.horizontal.FmmNode;
import com.flywheelms.library.fmm.node.interfaces.horizontal.FmmNodeGovernance;

public class NodeFragGovernance extends FmmNodeFragImpl implements FmmNodeGovernance {

//	private NodeId nodeId;
//	private String parentNodeIdString;
	private FmmNodeDictionary fmmNodeDictionaryEntry;
	private GovernanceTarget governanceTarget;
	private Hashtable<GovernanceRole, GovernanceTeamMember> governanceTeam = new Hashtable<GovernanceRole, GovernanceTeamMember>();
	
	public NodeFragGovernance(String aParentNodeIdString) {
		super(NodeFragGovernance.class, aParentNodeIdString);
		this.fmmNodeDictionaryEntry =
				FmmNodeDictionary.getEntryForNodeTypeCode(NodeId.getNodeTypeCodeFromNodeIdString(aParentNodeIdString));
	}
	
	public NodeFragGovernance(Class<? extends FmmNode> aClass) {
		super(NodeFragGovernance.class, NodeId.getTemporaryNodeIdString(aClass));
		this.fmmNodeDictionaryEntry =
				FmmNodeDictionary.getEntryForNodeTypeCode(NodeId.getNodeTypeCodeFromNodeIdString(this.getParentNodeIdString()));
	}

	// rehydrate
	public NodeFragGovernance(String anExistingNodeFragNodeIdString, String aParentNodeIdString) {
		super(NodeId.rehydrate(NodeFragGovernance.class, anExistingNodeFragNodeIdString), aParentNodeIdString);
		this.fmmNodeDictionaryEntry =
				FmmNodeDictionary.getEntryForNodeTypeCode(NodeId.getNodeTypeCodeFromNodeIdString(aParentNodeIdString));
	}
	
	public GovernanceTarget getGovernanceTarget() {
		if(this.governanceTarget == null) {
			this.governanceTarget = 
					GovernanceTarget.getObjectForFmmDictionaryEntry(this.fmmNodeDictionaryEntry);
		}
		return this.governanceTarget;
	}
	
	public Collection<GovernanceTeamMember> getGovernanceTeamCollection() {
		return this.governanceTeam.values();
	}
	
	public Set<GovernanceRole> getExistingGovernanceTeamRoles() {
		return this.governanceTeam.keySet();
	}
	
	public List<GovernanceRole> getRequiredGovernanceTeamRoles() {
		return this.governanceTarget.getRequiredGovernanceRoleList();
	}
	
	/////////////////////////////////////////////////////////////////////////////////////////
	
	private boolean isExistingGovernanceTeamRole(GovernanceRole aGovernanceRole) {
		return this.governanceTeam.keySet().contains(aGovernanceRole);
	}

	public GovernanceParticipationType getParticipationType(GovernanceRole aGovernanceRole) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			return this.governanceTeam.get(aGovernanceRole).participationType;
		}
		return null;
	}

	public void setParticipationType(GovernanceRole aGovernanceRole, GovernanceParticipationType aParticipationType) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			this.governanceTeam.get(aGovernanceRole).participationType = aParticipationType;
		}
	}

	public String getTeamMemberNodeIdString(GovernanceRole aGovernanceRole) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			return this.governanceTeam.get(aGovernanceRole).teamMember.getNodeIdString();
		}
		return null;
	}

	public CommunityMember getTeamMember(GovernanceRole aGovernanceRole) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			return this.governanceTeam.get(aGovernanceRole).teamMember;
		}
		return null;
	}

	public void setTeamMember(GovernanceRole aGovernanceRole, CommunityMember aCommunityMember) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			this.governanceTeam.get(aGovernanceRole).teamMember = aCommunityMember;
		}
		this.governanceTeam.put(aGovernanceRole, new GovernanceTeamMember(aGovernanceRole, aCommunityMember));
	}

	public AssignmentCommitmentType getAssignmentCommitmentType(GovernanceRole aGovernanceRole) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			return this.governanceTeam.get(aGovernanceRole).commitmentType;
		}
		return null;
	}

	public void setAssignmentCommitmentType(GovernanceRole aGovernanceRole, AssignmentCommitmentType anAssignmentCommitmentType) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			this.governanceTeam.get(aGovernanceRole).commitmentType = anAssignmentCommitmentType;
		}
	}

	public void setAssignmentCommitmentType(GovernanceRole aGovernanceRole, AssignmentCommitmentType anAssignmentCommitmentType, Date aCommitmentTimestamp) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			this.governanceTeam.get(aGovernanceRole).commitmentType = anAssignmentCommitmentType;
			this.governanceTeam.get(aGovernanceRole).commitmentTimestamp = aCommitmentTimestamp;
		}
	}

	public Date getCommitmentTimestamp(GovernanceRole aGovernanceRole) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			return this.governanceTeam.get(aGovernanceRole).commitmentTimestamp;
		}
		return null;
	}

	public void setCommitmentTimestamp(GovernanceRole aGovernanceRole, Date aCommitmentTimestamp) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			this.governanceTeam.get(aGovernanceRole).commitmentTimestamp = aCommitmentTimestamp;
		}
	}

	public String getProposedByNodeIdString(GovernanceRole aGovernanceRole) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			return this.governanceTeam.get(aGovernanceRole).proposedByCommunityMember.getNodeIdString();
		}
		return null;
	}

	public CommunityMember getProposedBy(GovernanceRole aGovernanceRole) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			return this.governanceTeam.get(aGovernanceRole).proposedByCommunityMember;
		}
		return null;
	}

	public void setProposedBy(GovernanceRole aGovernanceRole, CommunityMember aCommunityMember) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			this.governanceTeam.get(aGovernanceRole).proposedByCommunityMember = aCommunityMember;
		}
	}

	public Date getProposedTimestamp(GovernanceRole aGovernanceRole) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			return this.governanceTeam.get(aGovernanceRole).proposedTimestamp;
		}
		return null;
	}
	
	public void setProposedTimestamp(GovernanceRole aGovernanceRole, Date aProposedTimestamp) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			this.governanceTeam.get(aGovernanceRole).proposedTimestamp = aProposedTimestamp;
		}
	}
	
	public String getLockedByNodeIdString(GovernanceRole aGovernanceRole) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			return this.governanceTeam.get(aGovernanceRole).lockedByCommunityMember.getNodeIdString();
		}
		return null;
	}
	
	public CommunityMember getLockedBy(GovernanceRole aGovernanceRole) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			return this.governanceTeam.get(aGovernanceRole).lockedByCommunityMember;
		}
		return null;
	}
	
	public void setLockedByNodeIdString(GovernanceRole aGovernanceRole, CommunityMember aCommunityMember) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			this.governanceTeam.get(aGovernanceRole).lockedByCommunityMember = aCommunityMember;
		}
	}
	
	public Date getLockedTimestamp(GovernanceRole aGovernanceRole) {
		if(! isExistingGovernanceTeamRole(aGovernanceRole)) {
			return null;
		}
		return this.governanceTeam.get(aGovernanceRole).lockedTimestamp;
	}
	

	public void setLockedTimestamp(GovernanceRole aGovernanceRole, Date aLockedTimestamp) {
		if(isExistingGovernanceTeamRole(aGovernanceRole)) {
			this.governanceTeam.get(aGovernanceRole).lockedTimestamp = aLockedTimestamp;
		}
	}
	
	/////////////////////////////////////////////////////////////////////////////////////////
	
	private int getRequiredGovernanceCount() {
		return getRequiredGovernanceTeamRoles().size();
	}
	
	/*
	 *  TODO - need to OPTIMIZE by utilizing NodeFragTribKnQuality   SDS
	 *  This routine will become updateDecoratorGovernance()
	 *  New getDecoratorGovernance will just read the value from NodeFragTribKnQuality
	 */
	public DecoratorGovernance getDecoratorGovernance() {
//		GovernanceParticipationType sponsorRequirement;
//		GovernanceParticipationType facilitatorRequirement;
//		GovernanceParticipationType customerRequirement;
//		GovernanceParticipationType administratorRequirement;
		////  handle outstanding governance proposals  ////
		if(isNoGovernance()) {
			return DecoratorGovernance.NO_GOVERNANCE;
		}
		if(isProposedGovernance()) {
			return DecoratorGovernance.PROPOSED_GOVERNANCE;
		}
		return null;
	}
	
	private boolean isProposedGovernance() {
		for(GovernanceTeamMember theTeamMember : this.governanceTeam.values()) {
			if(theTeamMember.commitmentType == AssignmentCommitmentType.PROPOSED) {
				return true;
			}
		}
		return false;
	}

	private boolean isNoGovernance() {
		for(GovernanceTeamMember theTeamMember : this.governanceTeam.values()) {
			if(theTeamMember.teamMember != null) {
				return false;
			}
		}
		return true;
	}

	private boolean isGoodGovernance() {
		for(GovernanceRole theGovernanceRole : GovernanceTarget.getGovernanceTargetForNode(this.governanceTarget).getRequiredGovernanceRoleList()) {
			if(this.governanceTeam.get(theGovernanceRole) == null) {
				return false;
			}
		}
		for(GovernanceTeamMember theTeamMember : this.governanceTeam.values()) {
			if(theTeamMember.commitmentType != AssignmentCommitmentType.CONFIRMED) {
				return false;
			}
		}
		return true;
	}

	public String getGovernanceTargetNodeTypeName() {
		return this.fmmNodeDictionaryEntry.getNodeTypeName();
	}
	
	// rehydrate
	public void rehydrateGovernanceTeamMember(
			GovernanceRole aGovernanceRole,
			CommunityMember aCommunityMember,
			AssignmentCommitmentType aCommitmentType,
			Date aCommitmentTimestamp,
			CommunityMember aProposedByCommunityMember,
			Date aProposedTimestamp,
			CommunityMember aLockedByCommunityMember,
			Date aLockedTimestamp ) {
		GovernanceTeamMember theGovernanceTeamMember = new GovernanceTeamMember(aGovernanceRole, aCommunityMember);
		theGovernanceTeamMember.setCommitment(aCommitmentType, aCommitmentTimestamp);
		theGovernanceTeamMember.setProposed(aProposedByCommunityMember, aProposedTimestamp);
		theGovernanceTeamMember.setLocked(aLockedByCommunityMember, aLockedTimestamp);
		this.governanceTeam.put(theGovernanceTeamMember.getRole(), theGovernanceTeamMember);
	}

	public AssignmentCommitmentType getCommitmentType(GovernanceRole aGovernanceRole) {
		GovernanceTeamMember theGovernanceTeamMember = this.governanceTeam.get(aGovernanceRole);
		if(theGovernanceTeamMember == null) {
			return null;
		}
		return theGovernanceTeamMember.commitmentType;
	}

	public void setCommitmentType(
			GovernanceRole aGovernanceRole,
			AssignmentCommitmentType aCommitmentType,
			Date aCommitmentTimestamp ) {
		GovernanceTeamMember theGovernanceTeamMember = this.governanceTeam.get(aGovernanceRole);
		if(theGovernanceTeamMember == null) {
			return;
		}
		theGovernanceTeamMember.commitmentType = aCommitmentType;
		theGovernanceTeamMember.commitmentTimestamp = aCommitmentTimestamp;
	}

	@Override
	public String getHeadline() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setHeadline(String aHeadline) {
		// TODO Auto-generated method stub
		
	}
	
	public class GovernanceTeamMember {

		protected GovernanceRole role;
		protected GovernanceParticipationType participationType;
		protected CommunityMember teamMember;
		protected AssignmentCommitmentType commitmentType;
		protected Date commitmentTimestamp = FmmDateHelper.NULL_DATE;
		protected CommunityMember proposedByCommunityMember;
		protected Date proposedTimestamp = FmmDateHelper.NULL_DATE;
		protected CommunityMember lockedByCommunityMember = CommunityMember.getNullValue();
		protected Date lockedTimestamp = FmmDateHelper.NULL_DATE;
		
		public GovernanceTeamMember(GovernanceRole aGovernanceRole, CommunityMember aCommunityMember) {
			this.role = aGovernanceRole;
			this.teamMember = aCommunityMember;
		}

		public GovernanceTeamMember(GovernanceRole aGovernanceRole, String aCommunityMemberNodeIdString) {
			this(aGovernanceRole, FlywheelCommunityAuthentication.getInstance().getCommunityMember(aCommunityMemberNodeIdString));
		}

		public void setLocked(CommunityMember aCommunityMember, Date aLockedTimestamp) {
			this.lockedByCommunityMember = aCommunityMember;
			this.lockedTimestamp = aLockedTimestamp;
		}

		public void setLocked(String aCommunityMemberNodeIdString, Date aLockedTimestamp) {
			setLocked(FlywheelCommunityAuthentication.getInstance().getCommunityMember(aCommunityMemberNodeIdString), aLockedTimestamp);
		}

		public void setProposed(CommunityMember aCommunityMember, Date aProposedTimestamp) {
			this.proposedByCommunityMember = aCommunityMember;
			this.proposedTimestamp = aProposedTimestamp;
		}

		public void setProposed(String aCommunityMemberNodeIdString, Date aProposedTimestamp) {
			setProposed(FlywheelCommunityAuthentication.getInstance().getCommunityMember(aCommunityMemberNodeIdString), aProposedTimestamp);
		}

		public void setCommitment(AssignmentCommitmentType aCommitmentType, Date aCommitmentTimestamp) {
			this.commitmentType = aCommitmentType;
			this.commitmentTimestamp = aCommitmentTimestamp;
		}

		public void setCommitment(String aCommitmentTypeString, Date aProposedTimestamp) {
			setCommitment(AssignmentCommitmentType.getObjectForName(aCommitmentTypeString), aProposedTimestamp);
		}

		public GovernanceRole getRole() {
			return this.role;
		}

		public GovernanceParticipationType getParticipationType() {
			return this.participationType;
		}

		public CommunityMember getTeamMember() {
			return this.teamMember;
		}

		public AssignmentCommitmentType getCommitmentType() {
			return this.commitmentType;
		}

		public Date getCommitmentTimestamp() {
			return this.commitmentTimestamp;
		}

		public CommunityMember getProposedByCommunityMember() {
			return this.proposedByCommunityMember;
		}

		public Date getProposedTimestamp() {
			return this.proposedTimestamp;
		}

		public CommunityMember getLockedByCommunityMember() {
			return this.lockedByCommunityMember;
		}

		public Date getLockedTimestamp() {
			return this.lockedTimestamp;
		}

		public boolean isLocked() {
			if(! this.lockedByCommunityMember.equals(CommunityMember.getNullValue())) {
				return true;
			}
			return false;
		}
		
	}

	public void setGovernanceTargetFmmDictionaryEntry(String aNodeTypeName) {
		this.fmmNodeDictionaryEntry = FmmNodeDictionary.getEntryForNodeClassName(aNodeTypeName);
		
	}

	public boolean hasGovernanceRole(GovernanceRole aGovernanceRole) {
		return this.governanceTeam.get(aGovernanceRole) == null ? false : true;
	}

}
